from PyQt5.QtCore import QAbstractItemModel,QModelIndex, QByteArray, Qt,QObject, pyqtProperty, pyqtSignal as Signal,pyqtSlot as Slot, QPointF,QAbstractTableModel
from PyQt5.QtGui import QColor,QGuiApplication,QClipboard
from PyQt5 import QtCore
from PyQt5.QtQuick import (QQuickItem, QSGFlatColorMaterial,
                             QSGGeometry, QSGGeometryNode, QSGNode)
# from PyQt5.QtQml import QmlElement
import json
import logging
import pandas
from bpptablecolumn import BTColumn
roleDataType = Qt.UserRole
roleView=Qt.UserRole+1
roleCommand=Qt.UserRole+2
roleHighlight=Qt.UserRole+3
roleVisible=Qt.UserRole+4
roleRef1=Qt.UserRole+5
Sqlite = 0
JsonISO=1
class MySet:
    def __init__(self):
        self._data=[]
    def count(self,v):
        if v in self._data:
            return 1
        return 0
    def erase(self,v):
        self._data.remove(v)
        pass
    def insert(self,v):
        logging.info([v,self._data])
        if v in self._data:
            logging.info("already in")
            pass
        else:
            self._data.append(v)
            self._data.sort()
            logging.info(self._data)
    def size(self):
        return len(self._data)
    def empty(self):
        if len(self._data)==0:
            return True
        else:
            return False
    def begin(self):
        return self._data[0]
    def end(self):
        return self._data[len(self._data)-1]
    def rbegin(self):
        return self.end()
    def rend(self):
        return self.begin()
    def clear(self):
        self._data=[]
    pass
class BTModel(QAbstractTableModel):
    # layoutChanged=Signal()
    def __init__(self,parent=None):
        super().__init__(parent)
        self.dbRef=None
        self.dataChangedALS=False
        self.columnsChangedALS=False
        self.sortedChangedALS=False
        self._highlightRow=-1
        self.lastHighlightRow=-1
        self._hasMultiselection=False
        self._multiselectionMobileMode=False
        self.onlyHighlightRole=roleHighlight #onlyHighlightRole{CustomRoles.roleHighlight}
        self.sortColumns=[] #column ordinal, starting from 1 (not 0!)
        self._highlightRow=-1
        self.dataVal=[]
        self.dataIndex=[]
        self.columnsDef=[]
        self.highlightRows= MySet() #set()
        # self.columnsDef=[{"dataRef1":None},{"dataRef1":None},{"dataRef1":None}]
        self.demo()
    def demo(self):
        self.dataVal=[[1,2,3],[2,3,4]]
        self.dataIndex=[]
        c0=BTColumn()
        c0.title="0"
        c0.type="Int"
        c0.width=100
        c1=BTColumn()
        c1.title="1"
        c1.type="DateTime"
        c1.width=50
        c2=BTColumn()
        c2.width=100
        c2.title="2"
        self.columnsDef=[c0,c1,c2]
    highlightRowChanged=Signal()
    @pyqtProperty(int, final=True)
    def highlightRow(self):
        return self._highlightRow
    # @highlightRow.setter
    # def highlightRow(self, value):
    #     self._highlightRow=value
    #     # self.setHighlightRow(value,None)

    multiselectionMobileModeChanged=Signal()
    @pyqtProperty(bool, final=True)
    def multiselectionMobileMode(self):
        return self._multiselectionMobileMode
    @multiselectionMobileMode.setter
    def multiselectionMobileMode(self, value):
        self.setMultiselectionMobileMode(value)

    hasMultiselectionChanged=Signal()
    @pyqtProperty(bool, final=True,notify=hasMultiselectionChanged)
    def hasMultiselection(self):
        return self._hasMultiselection
    @multiselectionMobileMode.setter
    def hasMultiselection(self, value):
        self.setHasMultiselection(value)
    @Slot(result=int)
    def rowCount(self,*args, **kwargs):
        # logging.info("here")
        r=len(self.dataVal)#.size()
        # logging.info(r)
        return r
    @Slot(result=int)
    def columnCount(self,*args, **kwargs):
        # logging.info("here")
        r=len(self.columnsDef) #.size();
        # logging.info(r)
        return r

    # @Slot(result=int)
    # def rowCount(self):
    #     return len(self.dataVal)#.size()
    # @Slot(result=int)
    # def columnCount(self):
    #     return len(self.columnsDef) #.size();

    def data(self,cellIndex, role):
        logging.info(["here",cellIndex.row(),cellIndex.column()])
        cdef = self.getColumnDef(cellIndex.column() )

        if role==Qt.DisplayRole:
            return self.getDataDisplayRole(cellIndex)
        elif role==roleDataType:
            return cdef.type;
        elif role==roleView:
            return cdef.view;
        elif role== roleCommand:
            return cdef.command
        elif role==roleHighlight:
            if( self.highlightRows.count( cellIndex.row() ) ):
                return True
            return False;
        elif role== roleVisible:
            return cdef.visible;
        elif role== roleRef1:
            reference = cdef.reference1;
            if(reference >= 0):
                return self.getDataDisplayRole(cellIndex)# QModelIndex(cellIndex.row(), reference) ) 
            else:
                return ""

        return None

    #https:#doc.qt.io/qt-5/qt.html#ItemDataRole-enum
    def roleNames(self):
        names = {}
        names[hash(Qt.DisplayRole)] = "display".encode()
        names[hash(roleDataType)] = "dataType".encode()
        names[hash(roleView)] = "view".encode()
        names[hash(roleCommand)] = "command".encode()
        names[hash(roleHighlight)] = "highlight".encode()
        names[hash(roleVisible)] = "visible".encode()
        names[hash(roleRef1)] = "ref1".encode()
        return names
        # default = super().roleNames()
        # default[Qt.DisplayRole] = QByteArray(b"display")
        # default[CustomRoles.roleDataType] = QByteArray(b"dataType")
        # default[CustomRoles.roleView] = QByteArray(b"view")
        # default[CustomRoles.roleCommand] = QByteArray(b"command")
        # default[CustomRoles.roleHighlight] = QByteArray(b"highlight")
        # default[CustomRoles.roleVisible] = QByteArray(b"visible")
        # default[CustomRoles.roleRef1] = QByteArray(b"ref1")
        # return default        
        # return {
        #     {Qt.DisplayRole, "display"},
        #     {roleDataType, "dataType"},
        #     {roleView, "view"},
        #     {roleCommand, "command"},
        #     {roleHighlight, "highlight"},
        #     {roleVisible, "visible"},
        #     {roleRef1, "ref1"}
        # };
        pass
    def sortData(self):
        return
        if(self.dataChangedALS or self.columnsChangedALS or self.sortedChangedALS):
            self.setHighlightRow(-1, 0);

            doSort=True
            if(dataVal.isEmpty()): 
                doSort = False;

            if(doSort):
                if(sortColumns.isEmpty()): # no sort
                    doSort = false;
                    if(not dataIndex.isEmpty()) :
                        beginResetModel();
                        dataIndex.clear();
                        endResetModel();

            if(doSort):
                dataIndex.fill(0, dataVal.size());
                # std.iota(dataIndex.begin(), dataIndex.end(), 0);

                sortIndexes=[]
                for sortCol in  sortColumns:
                    orderAsc=True
                    iCol = sortCol;
                    if(iCol < 0):
                        orderAsc = False;
                        iCol = -iCol;

                    #-1 because sortColumns value starts from 1 for the first column
                    sortIndexes.push_back( QPair<int,bool>(iCol - 1, orderAsc) );

                self.beginResetModel();
                self.sort(dataIndex.begin(), dataIndex.end(), self.sortFunc)
                self.endResetModel();
            dataChangedALS = false;
            columnsChangedALS = false;
            sortedChangedALS = false;

    def sortFunc(self,indexA,  indexB):

        # recordA = self.dataVal[indexA];
        # recordB = self.dataVal[indexB];
        # for sortCol in  sortIndexes:
        #     orderAsc=sortCol.second
        #     iCol=sortCol.first

        #     valA = recordA[iCol];
        #     valB = recordB[iCol];

        #     if(valA.isNull() && !valB.isNull())
        #         return orderAsc;
        #     if(valB.isNull() && !valA.isNull())
        #         return !orderAsc;

        #     switch (getColumnDef( iCol ).type) {
        #     case "Str":
        #         if(valA.toString().compare(valB.toString(), Qt.CaseInsensitive) == 0):
        #             continue;
        #         break;
        #     case "Dbl":
        #         if( fabs(valA.toDouble() - valB.toDouble()) < double(FLT_EPSILON) )
        #             continue;
        #         break;
        #     case "Int":
        #         if( valA.toInt() == valB.toInt() )
        #             continue;
        #         break;
        #     case "Date":
        #         if( valA.toDate() == valB.toDate() )
        #             continue;
        #         break;
        #     case "DateTime":
        #         if( valA.toDateTime() == valB.toDateTime() )
        #             continue;
        #         break;

        #     if(orderAsc):
        #         switch (getColumnDef( iCol ).type) {
        #         case "Str":
        #             return valA.toString().compare(valB.toString(), Qt.CaseInsensitive) < 0;
        #         case "Dbl":
        #             return valA.toDouble() < valB.toDouble();
        #         case "Int":
        #             return valA.toInt() < valB.toInt();
        #         case "Date":
        #             return valA.toDate() < valB.toDate();
        #         case "DateTime":
        #             return valA.toDateTime() < valB.toDateTime();
        #     else:
        #         switch (getColumnDef( iCol ).type) {
        #         case "Str":
        #             return valA.toString().compare(valB.toString(), Qt.CaseInsensitive) > 0;
        #         case "Dbl":
        #             return valA.toDouble() > valB.toDouble();
        #         case "Int":
        #             return valA.toInt() > valB.toInt();
        #         case "Date":
        #             return valA.toDate() > valB.toDate();
        #         case "DateTime":
        #             return valA.toDateTime() > valB.toDateTime();
        return False;
    @Slot(bool)
    def beginReset(self, appendMode):
        self.beginResetModel();
        if(not appendMode):
            self.dataVal=[]#.clear();
            #dataIndex.clear();
        self.dataChangedALS = True;

    @Slot()
    def endReset(self):
        self.endResetModel()
        self.sortData()

    def addFromQuery(self,theSqlQuery, parameters):
        # if(!dbRef->getDb()) {
        #     qDebug() << "No database";
        #     return false;
        # }

        # QSqlQuery query(*dbRef->getDb());
        # query.setForwardOnly(true);

        # if(!query.prepare(theSqlQuery)){
        #     qDebug() << "Error querying the db" << query.lastError().text();
        #     return false;
        # }

        # if(!parameters.isEmpty()) {
        #     for(auto& curParam: parameters) {
        #         query.addBindValue(curParam);
        #     }
        # }

        # bool allOk(true);
        # if(query.exec()) {

        #     beginReset(false);

        #     if(!addFrontRecords.isEmpty())
        #         allOk = addFromList(addFrontRecords, false);

        #     dataVal.reserve(100);
        #     int nCols = columnsDef.size();
        #     while(query.next() && allOk) {
        #         dataVal.push_back(QVector<QVariant>());
        #         QVector<QVariant>& curRow = dataVal.last();
        #         curRow.reserve( nCols );

        #         for(int iCol = 0; iCol < nCols; iCol++) {
        #             #if(getColumnDef( iCol ).reference1 < 0)
        #                 appendDataVariant(curRow, query.value(iCol), getColumnDef( iCol ).type, DataDialect.Sqlite);
        #             #else
        #             #    appendDataVariant(curRow, emptyVInt, getColumnDef( iCol ).type, DataDialect.JsonISO);
        #         }
        #     }
        #     dataVal.shrink_to_fit();

        #     endReset();
        # }

        # if(query.lastError().isValid())
        # {
        #     allOk = false;
        #     qDebug() << "Error querying the db" << query.lastError().text();
        # }
        # query.finish();

        # return allOk;
        pass
    @Slot(str,bool)
    def addFromList(self,values, resetList):
        allOk=True
        logging.info([values,resetList])
        #if(resetList)
        values=json.loads(values)
        # self.beginReset(not resetList);
        self.beginResetModel();
        if(resetList):
            self.dataVal=[]#.clear();
            #dataIndex.clear();
        self.dataChangedALS = True;
        for curRecord in  values:
            logging.info(curRecord)
            curRow=[]
            # curRow = len(self.dataVal)
            # logging.info([curRow,curRecord])
            # for  k in curRecord.keys():
            #     logging.info([k,curRecord[k]])
            #     onerow.append(curRecord[k])
            # self.dataVal.append(onerow)                
            # logging.info(self.columnsDef)
            for  iCol in range(len(self.columnsDef)):#.size(); iCol++) {
                role=self.getColumnDef( iCol ).role
                logging.info(["role",role])
                if(not(role in curRecord.keys()) ):
                    self.appendDataVariant(curRow, None, self.getColumnDef( iCol ).type, JsonISO);
                else:
                    self.appendDataVariant(curRow, curRecord[role], self.getColumnDef( iCol ).type, JsonISO);
            self.dataVal.append(curRow)
        # #if(resetList)
        logging.info(self.dataVal)
        self.endResetModel()
        self.sortData()
        return allOk;

    def setFrontRecords(self,values):
        self.addFrontRecords = values;

    def countFromQuery(self,theSqlQuery, parameters):
        if(not dbRef.getDb()):
            print("No database")
            return False;

        query=QSqlQuery(dbRef.getDb());
        query.setForwardOnly(True);

        if(not query.prepare(theSqlQuery)):
            logging.info( ["Error querying the db" , query.lastError().text()])
            return 0;

        if(not parameters.isEmpty()):
            for curParam in  parameters:
                query.addBindValue(curParam)

        numRecords=0

        allOk=True
        if(query.exec()):
            if(query.next()):
                numRecords = int(query.value(0))
        if(query.lastError().isValid()):
            allOk = False;
            logging.info(["Error querying the db" , query.lastError().text()])
        query.finish();

        if(allOk):
            return numRecords;

        return 0;
    @Slot(str)
    def addRecord(self, theData):
        logging.info([theData,type(theData)])
        theData=json.loads(theData)
        # numColumns=len(self.columnsDef)
        # [1, "Apple", 2.45],
        self.dataChangedALS = True
        self.dataVal.append(theData)
        # curRow =[]
        # self.dataVal.append(curRow)
        # iCol=0;
        # for  theValue in theData:
        #     if(self.getColumnDef( iCol ).reference1 < 0):
        #         self.appendDataVariant(curRow, theValue, self.getColumnDef( iCol ).type, JsonISO);
        #     else:
        #         self.appendDataVariant(curRow, None, self.getColumnDef( iCol ).type,JsonISO);
        #     iCol+=1

        # # while(iCol < numColumns):
        # #     self.appendDataVariant(curRow,None, self.getColumnDef( iCol ).type, DataDialect.JsonISO);
        # #     iCol+=1
    @Slot()
    def updateLayout(self):
        self.layoutChanged.emit();
        self.sortData();


    def setDbRef(self,value):
        self.dbRef = value;
    @Slot()
    def endUpdateColumns(self):
        self.calcReferenceColumns();
        self.calcSortColumns();
        self.updateLayout();
    @Slot(result=bool)
    def canHideColumns(self):
        return True;
    @Slot(int)
    def copyRowToClipboard(self, row):
        text = self.getRowString(row)
        clipboard = QGuiApplication.clipboard();

        clipboard.setText(text, QClipboard.Clipboard);
        if (clipboard.supportsSelection()):
            clipboard.setText(text, QClipboard.Selection);

        return True;

    def getRowString(self,row):
        toRet=""

        toRet+="{"

        iCol=0
        appended=0;
        for col in self.columnsDef:
            if(col.command == 0):
                if(appended):
                    toRet+= ", " ;
                if(col.title is None):
                    toRet+= "column_"+str(iCol + 1)+":"
                else:
                    toRet+= col.title+":"
                if(col.type == "Str" or col.type == "Date" or col.type == "DateTime"):
                    toRet+= "\"" 
                    toRet+= str(self.data( self.index(row, iCol), Qt.DisplayRole))
                    toRet+= "\"" 
                else:
                    toRet+= str(self.data( self.index(row, iCol), Qt.DisplayRole))
                appended+=1;
            iCol+=1;
        toRet+="}"

        return toRet;

    def getRowObject(self, row):
        logging.info("here")
        toRet={}
        iCol = 0;
        for  col in self.columnsDef:
            toRet[col.role] = self.getDataDisplayRole( self.index(row, iCol) )
            iCol+=1
        return toRet;
    @Slot(int,int,str)
    def setCellValue(self, rowNum,  columnNum, data):
        data=json.dumps(data)
        logging.info([rowNum,columnNum,data])
        if(rowNum < 0) or (rowNum >= len(self.dataVal)):
            return False;
        if(columnNum < 0 or columnNum >= len(self.columnsDef)):
            return False;

        whatRow = rowNum;
        if(len(self.dataIndex)!=0):
            whatRow = self.dataIndex[whatRow];

        if( columnNum + 1 in self.sortColumns or -(columnNum + 1) in self.sortColumns):
            #data need to be resorted
            self.beginReset(True);
            self.dataVal[whatRow][columnNum] = data;
            self.endReset();
        else:
            self.dataVal[whatRow][columnNum] = data;
            self.dataChanged.emit( self.index(rowNum, columnNum) , self.index(rowNum, columnNum) , [Qt.DisplayRole]);
        return True;
    @Slot(int,result=int)
    def getColWidth(self, columnId):
        # logging.info("here")
        theW=0
        if(columnId<0):
            theW = 100;
        elif(self.columnsDef[columnId].visible):
            theW = self.columnsDef[columnId].width;

        #qDebug() << columnId << theW;
        return theW;
    @Slot()
    def clearColumnsDef(self):
        # logging.info("here")
        # for  col in self.columnsDef:
        #     delete col;
        # }
        self.columnsDef=[]
        self.columnsChangedALS = True;
    @Slot(result=int)
    def addColumnDef(self):
        # logging.info("here")
        newCol=len(self.columnsDef)
        self.columnsDef.append( BTColumn() )
        self.columnsChangedALS = True;
        return newCol;
    @Slot(int,bool,str)
    def setColumnDef(self, columnId,  withDefaults, colDef):
        # logging.info([colDef,type(colDef)])
        colDef=json.loads(colDef)
        # logging.info("here")
        self.columnsDef[columnId].modify(colDef, withDefaults)

    def getColumnDef(self, columnId):
        # logging.info("here")
        return self.columnsDef[columnId];
    @Slot(str,result=int)
    def getColumnId(self,columnRole):
        # logging.info("here")
        columnNum = -1;
        for  iCol in range(len(self.columnsDef)):
            if (columnRole == self.columnsDef[iCol].role):
                columnNum = iCol;
                break;
        return columnNum;

    def appendDataVariant(self,record, theValue, columnType, dia):
        # logging.info("here")
        if(theValue is None):
            record.append(None)
        else:
            record.append(theValue)

    def calcSortColumns(self):
        # logging.info("here")
        newSortColumns=[]
        for i in range(len(self.columnsDef)):#int i = 0; i < columnsDef.size(); i++){
            sortVal = self.getColumnDef(i).sortFlag;
            if(sortVal == 1):
                newSortColumns.append(i+1);
            if(sortVal == 2):
                newSortColumns.append(-(i+1));
        if(newSortColumns != self.sortColumns):
            self.sortColumns = newSortColumns;
            sortedChangedALS = True;

    def calcReferenceColumns(self):
        # logging.info("here")
        for iColumn in range(len(self.columnsDef)):
            # logging.info([self.columnsDef, iColumn])
            currentColumn = self.columnsDef[iColumn];
            # logging.info([currentColumn,type(currentColumn)])
            if(currentColumn.dataRef1 is None):
                currentColumn.reference1 = -1;
            else:
                currentColumn.reference1 = -1;
                iSeek=0
                # for(int iSeek = 0; ; iSeek++):
                while(iSeek < len(self.columnsDef) and currentColumn.reference1 == -1):
                    seekColumn = self.columnsDef[iSeek]
                    if(not seekColumn.role is None and currentColumn.dataRef1==seekColumn.role):
                        currentColumn.reference1 = iSeek;
                    iSeek+=1

    def getDataDisplayRole(self,index):
        logging.info(["here",index.row(),index.column()])
        whatRow = index.row();
        try:
            # logging.info([whatRow,index.column()])
            # if(not len(self.dataIndex)==0):
            #     whatRow = self.dataIndex[whatRow];

            colVal = self.dataVal[whatRow][index.column()];
            type1=self.getColumnDef( index.column() ).type
        
            if type1== "Str":
                if(colVal is None):
                    return None
                else:                
                    return str(colVal) #.toString();
            elif type1=="Dbl":
                if(colVal is None): 
                    return None
                else:                
                    return float(colVal) #.toDouble();
            elif type1=="Int":
                if(colVal is None): 
                    return None
                else:                
                    return int(colVal);
            elif type1=="Date":
                if(colVal is None): 
                    return None
                else:                
                    return colVal #.toDate();
            elif type1=="DateTime":
                if(colVal is None): 
                    return None
                else:                
                    return colVal #.toDateTime();
            return str(colVal)
        except IndexError as e:
            logging.info(e)
            pass
        except KeyError:
            logging.info(e)
            pass

    def setMultiselectionMobileMode(self, value):
        if(self.multiselectionMobileMode != value):
            self.multiselectionMobileMode = value;
            self.multiselectionMobileModeChanged.emit();


    def setHasMultiselection(self,value):
        if(value != self._hasMultiselection):
            self._hasMultiselection = value;
            if(not self._hasMultiselection and len(self.highlightRows)>1):
                self.setHighlightRow(-1, 0);
            self.hasMultiselectionChanged.emit()


    def isHighlightRow(self, rowNum):
        return self.highlightRows.count(rowNum)>0
        
    @Slot(result=int)
    def countHighlightRows(self):
        return self.highlightRows.size();
    @Slot(result=str)
    def getHighlightRows(self):
        toRet=[]
        for curRow in self.highlightRows._data:
            toRet.append(curRow);
        return json.dumps(toRet)
    @Slot()
    def dataNeedSort(self):
        self.columnsChangedALS = True;
    # Q_INVOKABLE void setHighlightRow(int rowNum, int modifiers);
    @Slot(int,int)
    def setHighlightRow(self, rowNum,  modifiers):

        pressedCtrl = modifiers & Qt.ControlModifier
        pressedShift = modifiers & Qt.ShiftModifier

        fireRowChanged=False
        minRow=-1 
        maxRow=-1

        if(self.multiselectionMobileMode):
            pressedCtrl = True;
        # rowNum=len(self.highlightRows) #.count(rowNum) #std::set<int>
        if(self.highlightRows.count(rowNum)):
            if(not self._hasMultiselection or pressedCtrl or self.highlightRows.size()== 1):
                #deselect it
                self.highlightRows.erase(rowNum);
                if(self.highlightRows.empty()):
                    self._highlightRow = -1;
                else:
                    self._highlightRow = self.highlightRows.begin();
                fireRowChanged = True;
                minRow = rowNum; 
                maxRow = rowNum;
                self.lastHighlightRow = -1;
            else:
                if(self._hasMultiselection):
                    minRow = self.highlightRows.begin();
                    maxRow = self.highlightRows.rbegin();
                    self.highlightRows.clear();
                    self.highlightRows.insert(rowNum);
                    self._highlightRow = rowNum;
                    self.lastHighlightRow = rowNum;
                    fireRowChanged = True;
        else:
            if(rowNum == -1):
                #select none
                if(not self.highlightRows.empty()):
                    #clear selection
                    minRow = self.highlightRows.begin();
                    maxRow = self.highlightRows.rbegin();
                    self.highlightRows.clear();
                    self._highlightRow = -1;
                    self.lastHighlightRow = -1;
                    fireRowChanged = True;
            elif(rowNum == -2):
                #select all
                for irow in range(len(self.dataVal)): #.size(); irow++):
                    self.highlightRows.insert(irow);
                fireRowChanged = True;
                self._highlightRow = len(self.dataVal)-1
                self.lastHighlightRow = self._highlightRow
                if(not self.highlightRows.empty()):
                    minRow = self.highlightRows.begin()
                    maxRow = self.highlightRows.rbegin()
            else :
                if(not self._hasMultiselection or (not pressedCtrl and not pressedShift)):
                    if(not self.highlightRows.empty()):
                        minRow = self.highlightRows.begin();
                        maxRow = self.highlightRows.rbegin();
                        self.highlightRows.clear();
                if(not self._hasMultiselection or not pressedShift or self.lastHighlightRow == -1):
                    self.highlightRows.insert(rowNum);
                else:
                    fromRow = self.lastHighlightRow;
                    toRow = rowNum;
                    if(fromRow > toRow):
                        tmp=fromRow
                        fromRow= toRow
                        toRow=tmp
                    minRow = fromRow;
                    maxRow = toRow;
                    while(fromRow <= toRow):
                        self.highlightRows.insert(fromRow);
                        fromRow+=1

                self._highlightRow = rowNum;
                self.lastHighlightRow = rowNum;
                fireRowChanged = True;
                if(minRow < 0 or rowNum < minRow): 
                    minRow = rowNum;
                if(maxRow < 0 or rowNum > maxRow): 
                    maxRow = rowNum;

        if(fireRowChanged):
            self.highlightRowChanged.emit();
            if(minRow != -1):
                pass
                #qDebug() << rowNum << minRow << maxRow;
                self.dataChanged.emit(self.index(minRow, 0), self.index(maxRow, len(self.columnsDef) - 1), [roleHighlight]);

    # Q_INVOKABLE void setHighlightRows(bool emptySel, const QVector<int>& rowsIdx);
    @Slot(bool,list)
    def setHighlightRows(self, emptySel, rowsIdx):

        fireRowChanged=False
        minRow=-1
        maxRow=-1

        if(emptySel):
            if(not len(highlightRows)==0):
                #clear selection
                minRow = self.highlightRows.begin();
                maxRow = self.highlightRows.rbegin();
                highlightRows.clear();
                highlightRow = -1;
                self.lastHighlightRow = -1;
                fireRowChanged = true;
        if(not len(rowsIdx)==0):
            for irow in range(len(rowsIdx)):
                highlightRows.insert(rowsIdx[irow]);
            fireRowChanged = True;
            highlightRow = rowsIdx[len(rowsIdx)-1];
            self.lastHighlightRow = highlightRow;
            if(not len(self.highlightRows)==0):
                if(minRow < 0 or self.highlightRows.begin() < minRow):
                    minRow = self.highlightRows.begin();
                if(maxRow < 0 or self.highlightRows.rbegin() > maxRow):
                    maxRow = self.highlightRows.rbegin();

        if(fireRowChanged):
            self.highlightRowChanged.emit()
            if(minRow != -1):
                #qDebug() << rowNum << minRow << maxRow;
                self.dataChanged.emit(QModelIndex(index(minRow, 0)), QModelIndex(index(maxRow, columnsDef.size() - 1)), [roleHighlight]);

